﻿using System.Text;
using System.Text.RegularExpressions;
using LuckyFish.GitNet.Models;

namespace LuckyFish.GitNet.ConsoleServes;

public class GitOrderServer
{
    #region Pror

    private string RepositoryPath { get; set; }
    private CommandRunner Runner { get; set; }
    private GitInfoServer Info { get; set; }
    public bool IsGitRepository { get; set; }

    #endregion

    #region GetFunction

    #region Info

    public string? GetGitLocation() => Info.Location;

    public string? GetGitVer() => Info.Ver;

    public bool GetGitInstall() => Info.InstallInfo == "Is Install";

    #endregion

    public OriginModel[] GetOrigins()
    {
        if (!IsGitRepository) return Array.Empty<OriginModel>();
        var run = Runner.Run("branch");
        return run.Split("\n").
            Where(x => !string.IsNullOrEmpty(x) || !string.IsNullOrWhiteSpace(x)).
            Select(s => new OriginModel(s)).ToArray();
    }
    
    public CodeFileModel[] GetStatus()
    {
        if (!IsGitRepository) return Array.Empty<CodeFileModel>();
        var run = Runner.Run("status -s");
        var array = run.Split("\n");
        List<CodeFileModel> models = new List<CodeFileModel>();
        foreach (var c in array.Where(x => !string.IsNullOrEmpty(x)))
        {
            var a = c.Split(" ").Where(x => !string.IsNullOrEmpty(x) && !string.IsNullOrWhiteSpace(x)).ToArray();
            var state = a[0];
            var filePath = a[1];
            string? changePath = null;
            if (a.Length >= 4)
            {
                filePath = a[^1];
                changePath = a[1];
            }

            var changeContent = Runner.Run($"diff {filePath}");
            models.Add(new CodeFileModel(filePath, new FileState(state, changeContent, changePath),
                !File.Exists(Path.Combine(RepositoryPath, filePath))));
        }

        return models.ToArray();
    }

    public BranchModel[] GetBranches()
    {
        if (!IsGitRepository) return Array.Empty<BranchModel>();
        var run = Runner.Run("branch");
        var array = run.Split("\n");
        List<BranchModel> models = new List<BranchModel>();
        foreach (var s in array.Where(x => !string.IsNullOrEmpty(x)))
        {
            var a = s.Split(" ").Where(x => !string.IsNullOrEmpty(x) && !string.IsNullOrWhiteSpace(x)).ToArray();
            if (a.Length == 1)
            {
                models.Add(new BranchModel(a[0], false));
                continue;
            }
            if (a.Length > 1) models.Add(new BranchModel(a[1], true));
        }
        return models.ToArray();
    }

    public CommitModel[] GetCommits()
    {
        if (!IsGitRepository) return Array.Empty<CommitModel>();
        var run = GbkToUft8(Runner.Run("log"));
        List<CommitModel> models = new List<CommitModel>();
        var list = run.Split("\n").Where(x => !string.IsNullOrEmpty(x) || !string.IsNullOrWhiteSpace(x)).ToList();

        for (int i = 0; i < list.Count / 4; i++)
        {
            var index = i * 4;
            var id = list[index][7..];
            var authorInfo = list[index + 1];
            var authorArray = Regex.Split(authorInfo, "Author: (.*)<(.*)>")
                .Where(x => !string.IsNullOrEmpty(x) || !string.IsNullOrWhiteSpace(x)).ToArray();
            var author = authorArray[0];
            var email = authorArray[1];
            var date = list[index + 2][8..];
            var name = list[index + 3][4..];
            models.Add(new CommitModel() { Author = author, CommitDate = date, Name = name, Id = id, Email = email });
        }

        return models.ToArray();
    }

    #endregion

    #region SetFunction

    public string Init()
    {
        if (IsGitRepository) return "";
        var s = Runner.Run($"init {RepositoryPath}");
        IsGitRepository = true;
        return s;
    }

    #region Basic

    public string Clone(string url)
        => !IsGitRepository ? "" : Runner.Run($"clone {url}");

    public string Add(string order)
        => !IsGitRepository ? "" : Runner.Run($"add {order}");

    public string Add()
        => !IsGitRepository ? "" : Runner.Run("add .");

    public string ResetHead(string filePath)
        => !IsGitRepository ? "" : Runner.Run($"reset HEAD {filePath}");

    public string Remove(string filePath, string order = "")
        => !IsGitRepository ? "" : Runner.Run($"rm {order} {filePath}");

    #endregion
    
    #region Branch

    public string CreateBranch(string name)
        => !IsGitRepository ? "" : Runner.Run($"branch {name}");

    public string CheckBranch(string branchName)
        => !IsGitRepository ? "" : Runner.Run($"checkout {branchName}");

    public string Merge(string branchName)
        => !IsGitRepository ? "" : Runner.Run($"merge {branchName}");

    public string RemoveBranch(string branchName)
        => !IsGitRepository ? "" : Runner.Run($"branch -d {branchName}");

    #endregion

    #region Origin

    public string AddOrigin(string alias,string url) => 
        IsGitRepository ? Runner.Run($"remote add {alias} {url}") : "";

    public string Fetch(string? name) => 
        IsGitRepository ? Runner.Run($"fetch {name}") : "";

    public string Pull(string originName,string branchNames) =>
        IsGitRepository ? Runner.Run($"pull {originName} {branchNames}") : "";

    public string Push(string originName, string branchName) =>
        IsGitRepository ? Runner.Run($"push {originName} {branchName}") : "";

    public string RemoveOrigin(string alias) => 
        IsGitRepository ? Runner.Run($"remote rm {alias}") : "";
    
    #endregion

    #endregion

    #region Function

    private static string GbkToUft8(string unicodeString)
    {
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        byte[] buffer = Encoding.GetEncoding("GBK").GetBytes(unicodeString);
        string keyword = Encoding.UTF8.GetString(buffer);
        return keyword;
    }

    #endregion

    public GitOrderServer(string dirPath)
    {
        RepositoryPath = dirPath;
        Runner = new CommandRunner("git", dirPath);
        Info = new GitInfoServer();
        IsGitRepository = bool.Parse(Runner.Run("rev-parse --is-inside-work-tree"));
    }
}